package de.dnb.music.version;

import de.dnb.basics.applicationComponents.RangeCheckUtils;
import de.dnb.music.additionalInformation.AdditionalInformation;
import de.dnb.music.additionalInformation.DateOfComposition;
import de.dnb.music.additionalInformation.Key;
import de.dnb.music.additionalInformation.OpusNumber;
import de.dnb.music.additionalInformation.ThematicIndexNumber;
import de.dnb.music.title.AugmentableElement;
import de.dnb.music.title.MusicTitle;
import de.dnb.music.visitor.TitleElement;
import de.dnb.music.visitor.Visitor;

public class Version extends AugmentableElement implements TitleElement {

	/**
	 * 
	 */
	private static final long serialVersionUID = 91555539907150543L;

	/**
	 * Was nach der rak-Phrase kommt. Wird in DBFassung gesetzt und dann
	 * von {@link ParseVersion} weiter ausgewertet.
	 */
	String rest = "";

	// Mögliche Fälle:

	/*	 Fall § M 511 a)
	 Hier folgt eine WV-Nummer oder eine op.-Zahl. Beispiel:
	 800 |p|Beethoven, Ludwig {van
	 801 |t|Fuge, Violine 1,2 Viola Violoncello op. 133. Op. 134	
	 
	 Untergruppen:
	 1: WV
	 2: op.
	 * 
	 */

	/* 
	 * Fall § M 511 b)
	 * ein Form- oder Gattungsbegriff gemäß Anlage M 10 im Singular, (!!!)
	 * gegebenenfalls erweitert um  eine  zusätzliche  Angabe  (Besetzung,  
	 * Tonart,  Entstehungsjahr);  vor  dem  Form-  oder Gattungsbegriff  steht
	 * Punkt,  Spatium  (.  ),  vor  der  zusätzlichen  Angabe  lediglich  ein 
	 * Spatium; 
	 * Unterruppe: 
	 * 1: keine weitere Angabe, nur Form- und Gattungsbegriff
	 * 2: Besetzung
	 * 3: Tonart
	 * 4: Entstehungsjahr
	 * 5: sonstige Zählung (nicht im Regelwerk, kommt aber beim DMA vor)
	 * 
	 * */

	//	 Fall § M 511 c)
	/*  eine  andere  erläuternde  Angabe  (z.B.  Entstehungsjahr  oder  
	 * Besetzung),  eingeleitet  durch das  Wort  "Fassung" (Anm: auch andere 
	 * Worte sind möglich);  vor  dem  Wort "Fassung"  steht  Punkt,  Spatium  
	 * (.  ),  vor  der erläuternden Angabe lediglich ein Spatium; 
	 * 
	 * Untergruppe:
	 * 1: Jahr
	 * 2: Besetzung
	 * 3: Irgend eine andere Angabe oder auch keine: "Frühfassung" 	 * 	  
	 * 4: die Kombination Besetzung + Jahr (9-mal in Datenbank)
	 * 5: "Fassung für Bläser" (Nicht im Regelwerk explizit, aber oft 
	 * 	  in der Datenbank). 66-mal kommt so etwas wie "Fassung 2" vor
	 * 
	 * */

	// -> für "Fassung" oder "Erw. Fassung" ...
	String rakPhrase = null;
	// für Untergruppe 3: (getrimmt), aber schon definiert:
	// 

	// Nicht nötig, da oben schon definiert:
	//  Gattungsliste genreList
	//  Zusatzangabe additionalInformation; 

	/* Der Fall § M 511 d) (alles andere) kann m.E. nicht geparst werden, da 
	 * er mit anderen möglichen Fällen, z.B. "op. 34" kollidiert.
	 *  
	 */

	/*
	 * Dummerweise kommen einige Fälle, die das heutige Regelwerk nicht 
	 * abdeckt, recht häufig vor: ähnlich wie bei c) steht nach dem ". " eine
	 * Jahreszahl oder eine Besetzung, allerdings ohne die einleitende 
	 * Phrase. Daher
	 * 
	 * 	Fall e) 
	 * 
	 * Untergruppe
	 *  1: Jahr
	 * 	2: Besetzung
	 */

	/*
	 * Manchmal ist die Fassungsphrase aus $s schon bekannt.
	 *  Auf ein genaues Parsen wird dann verzichtet.
	 *  
	 *  Fall $)
	 *  Untergruppe 1 
	 */
	String match = null;

	/**
	 * Gibt den Match, der aus einem nicht weiter analysierbaren $s
	 * gewonnen wird.
	 * 
	 * @return	Match oder null.
	 */
	public final String getMatch() {
		return match;
	}

	/**
	 * Konstruktor für den stufenweisen Aufbau in 
	 * {@link ParseVersion#parse(String, String)}.
	 */
	public Version() {
	}

	/**
	 * Wird für den Fall aufgerufen, dass die Fassung schon aus anderer Quelle
	 * bekannt ist.
	 * 
	 * @param versionStr unstrukturierter String, der die Fassung enthält.
	 */
	public Version(final String versionStr) {
		RangeCheckUtils.assertStringParamNotNullOrEmpty("versionStr",
				versionStr);
		this.match = versionStr;
	}

	public final char getFallgruppeParagraphM511() {
		if (rakPhrase != null)
			return 'c';
		if (containsGenre())
			return 'b';
		AdditionalInformation ai = getAdditionalInformation();
		if (ai != null) {
			if (ai instanceof OpusNumber || ai instanceof ThematicIndexNumber)
				return 'a';
			if (ai instanceof DateOfComposition)
				return 'e';
		} else if (containsInstrumentation())
			return 'e';
		return '$';

	}

	public final int getUntergruppe() {
		AdditionalInformation ai = getAdditionalInformation();
		char fallgruppe = getFallgruppeParagraphM511();
		if (fallgruppe == '$')
			return 1;
		if (fallgruppe == 'c') {
			if (containsAdditionalInformation() && containsInstrumentation())
				return 4;
			if (containsAdditionalInformation()) {
				if (ai instanceof DateOfComposition)
					return 1;
			}
			if (containsInstrumentation())
				return 2;
			if (rest.isEmpty())
				return 3;
			else
				return 5;
			/*
			 * Also ist der Rest ungeparst:
			 */

		}
		if (fallgruppe == 'b') {
			if (containsInstrumentation())
				return 2;
			if (ai == null)
				return 1;
			if (ai instanceof Key)
				return 3;
			if (ai instanceof DateOfComposition)
				return 4;
			return 5;
		}
		if (fallgruppe == 'a') {
			if (ai instanceof ThematicIndexNumber)
				return 1;
			else
				return 2;
		}
		// also e:
		if (containsInstrumentation())
			return 2;
		else
			return 1;
	}

	public final String getRakPhrase() {
		return rakPhrase;
	}

	public final String getRest() {
		return rest;
	}

	@Override
	public final void accept(final Visitor visitor) {
		boolean visitChildren = visitor.visit(this);
		if (visitChildren) {
			visitChildren(visitor);
		}
		visitor.leave(this);
	}

	@Override
	public final void addToTitle(final MusicTitle title) {
		RangeCheckUtils.assertReferenceParamNotNull("title", title);
		title.setVersion(this);
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		Version version = ParseVersion.parse(null, "a-Moll");
		System.out.println(version.getFallgruppeParagraphM511());
	}

}
